#pragma once
#include "Rom.h"
#include "mapper/Mapper.h"

class Famicom;
class NesCartridge
{
private:

    typedef struct {
		uint8_t nes[4];
		uint8_t PRGBankCount;
		uint8_t CHRBankCount;
		uint8_t flag1;
		uint8_t flag2;
	}NesHeader;

	Rom mRom = {0};
	Famicom * famicom;
	bool mLoadedrom = false;
public:
	Mapper* mapper = nullptr; //mapper
	Mirror Mmirror = Mirror::SINGLE_SCREEN_LOWER;
	NesCartridge(Famicom *fc);

	~NesCartridge();

	uint8_t PRG_num();
	void Release();

	Rom* GetRom();

	bool loadedrom();

	void Reset();
	int Validate(uint8_t* header, uint32_t hsize, uint32_t* psize);
	int LoadRom(uint8_t* const rom, const uint32_t size);


	void Save(SaveBundle* bundle);
	void Restore(SaveBundle* bundle);

	/// <summary>
	/// ˮƽͬ��
	/// </summary>
	/// <param name="line"></param>
	inline void Hsync(uint32_t line) {
		this->mapper->Hsync(line);
	}

	/// <summary>
	/// CPU��ַ�ռ䣨0x8000~0xFFFF�� д 
	/// </summary>
	/// <param name="address"></param>
	/// <param name="data"></param>
	inline void WriteViaCPU(uint16_t address, uint8_t data)
	{
		this->mapper->WriteViaCPU(address, data);
	}

	/// <summary>
	/// CPU��ַ�ռ䣨0x8000~0xFFFF�� ��
	/// </summary>
	/// <param name="address"></param>
	/// <returns></returns>
	inline uint8_t ReadViaCPU(uint16_t address)
	{
		return this->mapper->ReadViaCPU(address);
	}

	/// <summary>
	/// PPU��ַ�ռ� (0x8000 ~ 0x1FFF) д
	/// </summary>
	/// <param name="address"></param>
	/// <param name="data"></param>
	inline void WriteViaPPU(uint16_t address, uint8_t data)
	{
		this->mapper->WriteViaPPU(address, data);
	}

	/// <summary>
	/// PPU��ַ�ռ� (0x8000 ~ 0x1FFF) ��
	/// </summary>
	/// <param name="address"></param>
	/// <returns></returns>
	inline uint8_t ReadViaPPU(uint16_t address)
	{
		return this->mapper->ReadViaPPU(address);
	}

	/// <summary>
	/// ��չ�ڴ� д
	/// </summary>
	/// <param name="address"></param>
	/// <param name="data"></param>
	inline void Write6000(uint16_t address, uint8_t data)
	{
		this->mapper->Write6000(address, data);
	}

	/// <summary>
	/// ��չ�ڴ� ��
	/// </summary>
	/// <param name="address"></param>
	/// <returns></returns>
	inline uint8_t Read6000(uint16_t address) {
		return this->mapper->Read6000(address);
	}



};


